﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;

namespace Server.Utils.JSON
{
    public class JSONEncoder
    {
        string m_str = null;

        public JSONEncoder(JSONObject obj)
        {
            m_str = Convert2String(obj);
        }

        public string GetString()
        {
            return m_str;
        }

        private string Convert2String(object obj)
        {
            if (obj.GetType() == typeof(String))
            {
                return EscapeString((string)obj);
            }
            else if (obj.GetType() == typeof(double))
            {
                return Double.IsInfinity((double)obj) ? "null" : obj.ToString();
            }
            else if (obj.GetType() == typeof(bool))
            {
                return (bool)obj ? "true" : "false";
            }
            else if (obj.GetType() == typeof(ArrayList))
            {
                return Array2String((ArrayList)obj);
            }
            else if (obj.GetType() == typeof(JSONObject))
            {
                return Object2String((JSONObject)obj);
            }
            else
            {
                throw new JSONParseException(0, "Unexpected object type [" + obj.GetType().ToString() + "]");
            }
        }

        private string EscapeString(string str)
        {
            string s = "";
            char ch = '\0';
            int len = str.Length;

            for (int i = 0; i < len; ++i)
            {
                ch = str[i];

                switch (ch)
                {
                    case '"':
                        s += "\\\"";
                	    break;
                    case '\\':
                        s += "\\\\";
                        break;
                    case '\b':
                        s += "\\b";
                        break;
                    case '\f':
                        s += "\\f";
                        break;
                    case '\n':
                        s += "\\n";
                        break;
                    case '\r':
                        s += "\\r";
                        break;
                    case '\t':
                        s += "\\t";
                        break;
                    default:
                        if (ch < ' ')
                        {
                            string hexCode = Convert.ToInt32(ch.ToString(), 16).ToString();
                            string zeroPad = hexCode.Length == 2 ? "00" : "000";

                            s += "\\u" + zeroPad + hexCode;
                        }
                        else
                        {
                            s += ch;
                        }
                        break;
                }
            }

            return "\"" + s + "\"";
        }

        private string Array2String(ArrayList arr)
        {
            string s = "";

            for (int i = 0; i < arr.Count; ++i)
            {
                if (s.Length > 0)
                {
                    s += ",";
                }

                s += Convert2String(arr[i]);
            }

            return "[" + s + "]";
        }

        private string Object2String(JSONObject obj)
        {
            string s = "";

            foreach (KeyValuePair<string, object> value in obj)
            {
                if (s.Length > 0)
                {
                    s += ",";
                }

                s += EscapeString(value.Key) + ":" + Convert2String(value.Value);
            }

            return "{" + s + "}";
        }
    }
}